/**
 * <copyright>
 * </copyright>
 *
 * $Id$
 */
package tin92c01.impl;

import java.util.ArrayList;
import java.util.Collection;

import node1.impl.Node1Impl;

import org.eclipse.emf.common.notify.NotificationChain;

import org.eclipse.emf.common.util.EList;

import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.InternalEObject;

import org.eclipse.emf.ecore.util.EObjectContainmentEList;
import org.eclipse.emf.ecore.util.InternalEList;

import resultsWCRT.ResultsWCRT;
import resultsWCRT.ResultsWCRTFactory;
import resultsWCRT.Scheduling;
import tin92c01.Task;
import tin92c01.Tin92c01;
import tin92c01.Tin92c01Package;
import utils.UtilsMaths;
import utils.UtilsModelInstance;

/**
 * <!-- begin-user-doc -->
 * An implementation of the model object '<em><b>Tin92c01</b></em>'.
 * <!-- end-user-doc -->
 * <p>
 * The following features are implemented:
 * <ul>
 *   <li>{@link tin92c01.impl.Tin92c01Impl#getTasks <em>Tasks</em>}</li>
 * </ul>
 * </p>
 *
 * @generated
 */
public class Tin92c01Impl extends Node1Impl implements Tin92c01 {
	/**
	 * The cached value of the '{@link #getTasks() <em>Tasks</em>}' containment reference list.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getTasks()
	 * @generated
	 * @ordered
	 */
	protected EList<Task> tasks;

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	protected Tin92c01Impl() {
		super();
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	protected EClass eStaticClass() {
		return Tin92c01Package.Literals.TIN92C01;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public EList<Task> getTasks() {
		if (tasks == null) {
			tasks = new EObjectContainmentEList<Task>(Task.class, this, Tin92c01Package.TIN92C01__TASKS);
		}
		return tasks;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public NotificationChain eInverseRemove(InternalEObject otherEnd, int featureID, NotificationChain msgs) {
		switch (featureID) {
			case Tin92c01Package.TIN92C01__TASKS:
				return ((InternalEList<?>)getTasks()).basicRemove(otherEnd, msgs);
		}
		return super.eInverseRemove(otherEnd, featureID, msgs);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public Object eGet(int featureID, boolean resolve, boolean coreType) {
		switch (featureID) {
			case Tin92c01Package.TIN92C01__TASKS:
				return getTasks();
		}
		return super.eGet(featureID, resolve, coreType);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void eSet(int featureID, Object newValue) {
		switch (featureID) {
			case Tin92c01Package.TIN92C01__TASKS:
				getTasks().clear();
				getTasks().addAll((Collection<? extends Task>)newValue);
				return;
		}
		super.eSet(featureID, newValue);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public void eUnset(int featureID) {
		switch (featureID) {
			case Tin92c01Package.TIN92C01__TASKS:
				getTasks().clear();
				return;
		}
		super.eUnset(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public boolean eIsSet(int featureID) {
		switch (featureID) {
			case Tin92c01Package.TIN92C01__TASKS:
				return tasks != null && !tasks.isEmpty();
		}
		return super.eIsSet(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated NOT
	 */
	public void compute() 
	{
		/* We assume that tasks are in priority order*/
		boolean isOver = false;

		ResultsWCRT rWCRT = UtilsModelInstance.createResultsWCRT();
		UtilsModelInstance.linkComputeBox(this, rWCRT, false);

		for (int i = 0 ; i < this.tasks.size() ; i++)
		{
			/**/
			ArrayList<Integer> l_wcrt = new ArrayList<Integer>();
			/* Step 1: compute the first approximation*/
			int a_0 = this.tasks.get(i).getBlocking();
			for(int j = 0; j <= i ; j++)
			{
				a_0 += this.tasks.get(j).getWcet();
			}

			boolean toBeContinued = true;
			int k = 1;
			int a_n = 0;
			int cpt = 1;
			while(toBeContinued)
			{

				/* Step 3 : compute the next approximation*/
				/* Step 4 : Determine if the approximation is the completion time of the kth job */

				do
				{

					if (cpt != 1) 
					{
						a_0 = a_n;
					}
					a_n = this.tasks.get(i).getBlocking() + k*this.tasks.get(i).getWcet();
					if (i != 1)
					{
						for (int j = 1 ; j < i-1 ; j++)
						{
							a_n += UtilsMaths.ceiling(a_0, this.tasks.get(j).getPeriod()) * this.tasks.get(j).getWcet();
						}
					}
//					System.out.println(this.tasks.get(i).getId());
//					System.out.println("> k : " + k);
//					System.out.println("> a_0 : " + a_0);
//					System.out.println("> a_n : " + a_n);
					cpt++;
					/**/
				}while((a_0 != a_n) && (a_n <= ((k - 1) * this.tasks.get(i).getWcet() + this.tasks.get(i).getDeadline())));

				if (a_n >= ((k - 1) * this.tasks.get(i).getWcet() + this.tasks.get(i).getDeadline())){
					isOver = true;
					toBeContinued = false;
				}

				if (!isOver)
				{
					int wcrt = a_n - this.tasks.get(i).getPeriod() * (k - 1);
					l_wcrt.add(wcrt);
					if (wcrt <= this.tasks.get(i).getPeriod())
					{
						toBeContinued = false;
					}
					else
					{
						a_n = a_n + this.tasks.get(i).getWcet();
						k++;
					}
				}
			}	
			/**/
			resultsWCRT.Task lt = ResultsWCRTFactory.eINSTANCE.createTask();
			lt.setId(this.tasks.get(i).getId());
			if (!isOver)
			{
				int maxWCRT = 0;
				for (Integer wcrt : l_wcrt)
				{
					if (wcrt > 0) maxWCRT = wcrt;
					}
				/**/
				lt.setWcrt(maxWCRT);
				lt.setScheduling(Scheduling.SCHEDULABLE);
				rWCRT.getTasks().add(lt);
			

			}
			/* If the algorithm is over*/
			if (isOver) 
			{
				lt.setScheduling(Scheduling.NON_SCHEDULABLE);
				rWCRT.getTasks().add(lt);
				break;
			}
		}

	}

} //Tin92c01Impl
